// TODO: CODE REVIEW & CLEANUP!
//
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using AxWMPLib;
using WMPLib;

namespace HomeUX.MusicServer
{

public partial class AppForm : Form
{
    MusicServer _musicServer;
    double _currentTrackDuration;
    //int _currentTrackQueueIndex;
    int _queueTrackCount;
    double _queueTotalSeconds;

    bool _isQuitting;

    public AppForm()
    {
        // standard initialization
        InitializeComponent();

        // name the main thread to help with debugging
        System.Threading.Thread.CurrentThread.Name = "Main Thread";
    }

    private void AppForm_Load(object sender, EventArgs e)
    {
        if (Program.OpenWindowOnLaunch)
            ShowMainWindow();

        Label pleaseWait = new Label()
        {
            Text = "Please wait...",
            Width = Width,
            Height = Height,
            TextAlign = ContentAlignment.MiddleCenter,
            Font = new Font(Font.FontFamily, 12)
        };
        Controls.Add(pleaseWait);
        Controls.SetChildIndex(pleaseWait, 0);

        if (Program.OpenWindowOnLaunch)
            Update();

        try
        {
            _musicServer = new MusicServer(MediaPlayer, delegate(Action del)
                {
                    BeginInvoke(del);
                });
            _musicServer.ClientCountChange += _musicServer_ClientCountChange;
            _musicServer.CurrentTrackIdChange += _musicServer_CurrentTrackIdChange;
            _musicServer.CurrentStatusChange += _musicServer_CurrentStatusChange;
            _musicServer.CurrentPositionChange += _musicServer_CurrentPositionChange;
            _musicServer.CurrentTrackQueueIndexChange += _musicServer_CurrentTrackQueueIndexChange;
            _musicServer.QueueChange += _musicServer_QueueChange;
            _musicServer.Initialize();
            _musicServer_ClientCountChange(null, null);
            _musicServer_CurrentTrackIdChange(null, null);
            _musicServer_CurrentStatusChange(null, null);

            UseWaitCursor = false;
        }
        catch (MusicServerException ex)
        {
            Program.ReportError(ex.Message);
            KillApplication();
        }
        catch (UnauthorizedAccessException ex)
        {
            Program.ReportError(
                "Insufficient privileges to run this application.  It may need to run with elevated privilges.\r\n\r\nDetails: {0}",
                ex.Message);
            KillApplication();
        }
#if !NOCATCH
        catch (Exception ex)
        {
            Program.ReportError("Internal error: \r\n\r\n{0}", ex.ToString());
            KillApplication();
        }
#else
#warning Exception handling is disabled
#endif
        finally
        {
            pleaseWait.Visible = false;
        }
    }

    // kill application quickly, e.g. due to an exception
    void KillApplication()
    {
        TrayIcon.Visible = false;
        Environment.Exit(1);
    }

    void _musicServer_ClientCountChange(object sender, EventArgs e)
    {
        ConnectedClientsLabel.Text = _musicServer.ClientCount.ToString();
        TrayIcon.Text = String.Format("HomeUX Music Server - {0} client(s)", _musicServer.ClientCount);
    }

    void _musicServer_CurrentTrackIdChange(object sender, EventArgs e)
    {
        TrackDetails trackDetails;
        AlbumDetails albumDetails;
        if (_musicServer.CurrentTrackId != null)
        {
            albumDetails = _musicServer.GetAlbumDetails(
                _musicServer.CurrentTrackId.AlbumId);
            ArtistLabel.Text = albumDetails.ArtistName;
            AlbumLabel.Text = albumDetails.Name;
            trackDetails = albumDetails.Tracks.FirstOrDefault(
                t => t.TrackNumber == _musicServer.CurrentTrackId.TrackNumber);
        }
        else
        {
            trackDetails = null;
            albumDetails = null;
        }

        if (trackDetails != null)
        {
            TrackNumberLabel.Text = String.Format("{0} of {1}", trackDetails.TrackNumber,
                albumDetails.Tracks.Length);
            TrackTitleLabel.Text = trackDetails.Name;
            _currentTrackDuration = trackDetails.Duration;
            DisplayPosition(0);
            ComposerLabel.Text = trackDetails.Composer;
            YearLabel.Text = String.Format("{0}", trackDetails.Year);
        }
        else
        {
            TrackNumberLabel.Text = String.Empty;
            TrackTitleLabel.Text = String.Empty;
            _currentTrackDuration = 0;
            DisplayPosition(0);
            ComposerLabel.Text = String.Empty;
            YearLabel.Text = String.Empty;
        }

        DisplayStatus();
    }

    void _musicServer_CurrentStatusChange(object sender, EventArgs e)
    {
        DisplayStatus();
    }

    void _musicServer_CurrentPositionChange(object sender, EventArgs e)
    {
        DisplayPosition(_musicServer.CurrentPosition);
    }

    void _musicServer_CurrentTrackQueueIndexChange(object sender, EventArgs e)
    {
        //_currentTrackQueueIndex = _musicServer.CurrentTrackQueueIndex;
        DisplayStatus();
    }

    void _musicServer_QueueChange(object sender, QueueChangeEventArgs e)
    {
        _queueTrackCount = e.QueueDetails.Tracks.Length;
        _queueTotalSeconds = 0;
        foreach (AlbumTrackDetails track in e.QueueDetails.Tracks)
            _queueTotalSeconds += track.TrackDetails.Duration;
        DisplayStatus();
    }

    void DisplayStatus()
    {
        string format;
        switch (_musicServer.CurrentPlayState)
        {
        case MusicServicePlayState.Playing:
            format = "Playing track {0} of {1} ({2} minutes total)";
            break;
        case MusicServicePlayState.Paused:
            format = "Paused at track {0} of {1} ({2} minutes total)";
            break;
        case MusicServicePlayState.Stopped:
            format = "Stopped at track {0} of {1} ({2} minutes total)";
            break;
        default:
            format = "{1} track(s) ({2} minutes total)";
            break;
        }

        QueueStatusLabel.Text = String.Format(format, _musicServer.CurrentTrackQueueIndex + 1,
            _queueTrackCount, FormatDuration(_queueTotalSeconds));
    }

    void DisplayPosition(double position)
    {
        if (_currentTrackDuration == 0)
            TrackPositionLabel.Text = String.Empty;
        else
        {
            TrackPositionLabel.Text = String.Format("{0} of {1}",
                FormatDuration(position), FormatDuration(_currentTrackDuration));
        }
    }

    public static string FormatDuration(double seconds)
    {
        return FormatDuration((int)seconds);
    }

    public static string FormatDuration(int seconds)
    {
        int min = seconds / 60;
        int sec = seconds % 60;
        if (min < 60)
            return String.Format("{0}:{1:00}", min, sec);
        else
            return String.Format("{0}:{1:00}:{2:00}", min / 60, min % 60, sec);
    }

    private void ExitMenuItem_Click(object sender, EventArgs e)
    {
        ExitApplication();
    }

    public void ExitApplication()
    {
        _isQuitting = true;
        Close();
    }

    private void PollTimer_Tick(object sender, EventArgs e)
    {
        if (_musicServer != null)
            _musicServer.Poll();
    }

    private void ShowStatusMenuItem_Click(object sender, EventArgs e)
    {
        ShowMainWindow();
    }

    private void TrayIcon_DoubleClick(object sender, EventArgs e)
    {
        ShowMainWindow();
    }

    private void AppForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (!_isQuitting && (e.CloseReason == CloseReason.UserClosing))
        {
            // the user closed the window -- let the application continue running in the taskbar
            HideMainWindow();
            e.Cancel = true;
            return;
        }

        // try to avoid the "RaceOnRCWCleanup was detected" error
        MediaPlayer.Parent = null;
    }

    void ShowMainWindow()
    {
        Show();
        WindowState = FormWindowState.Normal;
        ShowInTaskbar = true;

        // force the window to the foreground
        TopMost = true;
        TopMost = false;
    }

    void HideMainWindow()
    {
        Hide();
        ShowInTaskbar = false;
    }

    private void CheckForNewMusicButton_Click(object sender, EventArgs e)
    {
        CheckForNewMusic();
    }

    private void ExitButton_Click(object sender, EventArgs e)
    {
        ExitApplication();
    }

    private void CheckForNewMusicMenuItem_Click(object sender, EventArgs e)
    {
        CheckForNewMusic();
    }

    void CheckForNewMusic()
    {
        UseWaitCursor = true;

        // execute EnumerateLibrary asynchronously to allow the wait cursor to appear
        CheckForNewMusicTimer.Enabled = true;
    }

    private void CheckForNewMusicTimer_Tick(object sender, EventArgs e)
    {
        CheckForNewMusicTimer.Enabled = false;
        try
        {
            _musicServer.EnumerateLibrary();
        }
        finally
        {
            UseWaitCursor = false;

            Program.ReportInformation("The Media Player library contains: {0} artist(s), {1} album(s)\n\n" +
                "Note that this check for Media Player library changes is done automatically when HomeUX Music Server launches.",
                _musicServer.ArtistCount, _musicServer.AlbumCount);
        }
    }

    private void AboutMenuItem_Click(object sender, EventArgs e)
    {
        Program.ReportInformation("HomeUX Music Server by Rick Ledoux");
    }
}

}
